package ru.aptu.gsp_banking.service_impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import ru.aptu.billing.BillingClientFactory;
import ru.aptu.billing_client.BillingClient;
import ru.aptu.billing_message.*;
import ru.aptu.gsp_banking.dao.AccountDAO;
import ru.aptu.gsp_banking.dao.TransactionDAO;
import ru.aptu.gsp_banking.domain.Account;
import ru.aptu.gsp_banking.domain.PublicService;
import ru.aptu.gsp_banking.domain.Transaction;
import ru.aptu.gsp_banking.service.CurrencyService;
import ru.aptu.gsp_banking.service.PublicServiceService;
import ru.aptu.gsp_banking.snmp.Sender;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by IntelliJ IDEA.
 * User: alex
 * Date: 2/10/12
 * Time: 9:25 PM
 */

@Service
public class PublicServiceServiceImpl implements PublicServiceService {

    @Autowired
    private AccountDAO accountDAO;

    @Autowired
    private TransactionDAO transactionDAO;

    @Autowired
    private CurrencyService currencyService;

    class NegativeResponseException extends Exception {}

    private void checkMessage(ResponseMessage message) throws NegativeResponseException {
        if (message == null) {
            Sender.sendV2cTrap("Error receiving message");
            throw new NegativeResponseException();
        } else {
            Sender.sendV2cTrap("Receiving message: " + message.getStatus());
            if (!message.getStatus().equals(BasicMessage.Status.OK))
                throw new NegativeResponseException();
        }
    }

    @Transactional
    public PublicService getBill(PublicService publicService) {

        BillingClient client = BillingClientFactory.createDefaultBillingClient();
        if (!client.initConnection()) {
            Sender.sendV2cTrap("Error connecting to billing server.");
            return null;
        }

        try {
            ResponseMessage message = client.sendMessage(new RequestMessage(BasicMessage.MessageType.CHECK_PROTOCOL));
            checkMessage(message);

            BasicMessage.ServiceType serviceType = BasicMessage.ServiceType.EMPTY;
            if (publicService.getServiceType().equals("WATER")) {
                serviceType = BasicMessage.ServiceType.WATER;
            } else if (publicService.getServiceType().equals("ELECTRICITY")) {
                serviceType = BasicMessage.ServiceType.ELECTRICITY;
            }

            message = client.sendMessage(new RequestMessage(
                    BasicMessage.MessageType.CHECK_ACCOUNT, serviceType, publicService.getServiceId()));
            checkMessage(message);

            publicService.setRate(new Float(((ResponseCreditMessage) message).getRate()));
            publicService.setLastValue(new Float(((ResponseCreditMessage) message).getLastValue()));
            publicService.setCurrency(((ResponseCreditMessage) message).getCurrency());
            publicService.setNewValue(new Float(0.0));

        } catch (NegativeResponseException e) {
            return null;
        } finally {
            client.close();
        }
        return publicService;
    }

    @Transactional
    public boolean submitPublicService(PublicService publicService) {

        Account accountFrom = accountDAO.getAccountById(publicService.getAccountId());

        if (accountFrom.getBalance()
                < currencyService.convert(publicService.getAmount(), publicService.getCurrency(), accountFrom.getCurrency())
                || publicService.getAmount() <= 0) {
            return false;
        }

        BillingClient client = BillingClientFactory.createDefaultBillingClient();
        if (!client.initConnection()) {
            Sender.sendV2cTrap("Error connecting to billing server.");
            return false;
        }

        try {
            BasicMessage.ServiceType serviceType = BasicMessage.ServiceType.EMPTY;
            if (publicService.getServiceType().equals("WATER")) {
                serviceType = BasicMessage.ServiceType.WATER;
            } else if (publicService.getServiceType().equals("ELECTRICITY")) {
                serviceType = BasicMessage.ServiceType.ELECTRICITY;
            }

            Transaction transaction = new Transaction(
                    publicService.getAccountId(), -publicService.getAmount(), publicService.getCurrency(),
                    "Public Service: " + publicService.getServiceType() + " #" + publicService.getServiceId());

            transactionDAO.saveTransaction(transaction);

            try {
                ResponseMessage message = client.sendMessage(new PaymentRequestMessage(serviceType,
                        publicService.getServiceId(), transaction.getId(), publicService.getAmount(), publicService.getCurrency()));
                checkMessage(message);
            } catch (NegativeResponseException e) {
                transactionDAO.deleteTransaction(transaction);
                throw e;
            }

            return true;
        } catch (NegativeResponseException e) {
            return false;
        } finally {
            client.close();
        }
    }

    @Transactional
    public List<String> listPublicServiceTypes() {
        List<String> list = new ArrayList<String>();
        list.add("WATER");
        list.add("ELECTRICITY");
        return list;
    }
}
